é«åºŠãªWebã€ã³ã¿ã©ã¯ã·ã§ã³ãè§£ãæŸã¡ãŸãããã®å æ¬çãªã¬ã€ãã§ã¯ãCSSã¹ã¯ããŒã«é§åã¢ãã¡ãŒã·ã§ã³ã®ã¿ã€ã ã©ã€ã³åæãæ·±æãããview()ãscroll()ããããŠé åçã§é«ããã©ãŒãã³ã¹ãªãŠãŒã¶ãŒäœéšãåµé ããããã®å®è·µçãã¯ããã¯ã解説ããŸãã
CSSã¹ã¯ããŒã«é§åã¢ãã¡ãŒã·ã§ã³ããã¹ã¿ãŒããïŒã¿ã€ã ã©ã€ã³åæã®æ·±æã解説
é·å¹Žã«ããããWebäžã§é åçãªã¹ã¯ããŒã«é£åã¢ãã¡ãŒã·ã§ã³ãäœæããããšã¯ãJavaScriptã®é åã§ãããéçºè ã¯ã©ã€ãã©ãªãè€éãª`requestAnimationFrame`ã«ãŒãã«é Œããåžžã«ã¹ã¯ããŒã«ã€ãã³ããç£èŠããŠããŸããããã®ã¢ãããŒãã¯å¹æçã§ããäžæ¹ãããã©ãŒãã³ã¹äžã®ã³ã¹ãã䌎ãããšãå€ããç¹ã«æ§èœã®äœãããã€ã¹ã§ã¯ã«ã¯ã€ããã¹ã ãŒãºãã«æ¬ ããäœéšã«ã€ãªãããã¡ã§ããã仿¥ããã®ãŠãŒã¶ãŒã€ã³ã¿ãŒãã§ãŒã¹ãã¶ã€ã³ã®ã«ããŽãªãŒå šäœãããã©ãŠã¶ã®é«æ§èœãªã¬ã³ããªã³ã°ãšã³ãžã³ã«çŽæ¥ç§»è¡ããããã©ãã€ã ã·ãããé²è¡ããŠããŸãããã®ç«åœ¹è ãCSSã¹ã¯ããŒã«é§åã¢ãã¡ãŒã·ã§ã³ã§ãã
ãã®åŒ·åãªæ°ãã仿§ã«ãããã¢ãã¡ãŒã·ã§ã³ã®é²è¡åºŠãã³ã³ããã®ã¹ã¯ããŒã«äœçœ®ãèŠçŽ ã®å¯èŠæ§ã«çŽæ¥ãªã³ã¯ãããããšãã§ããŸãããã®çµæãå®å šã«ã¹ã ãŒãºã§ãGPUã¢ã¯ã»ã©ã¬ãŒã·ã§ã³ã«ããã宣èšçã§ã¢ã¯ã»ã¹ããããããããŠé©ãã»ã©å¹ççãªã¢ãã¡ãŒã·ã§ã³ãå®çŸããŸããããããçã®åµé çå¯èœæ§ãè§£ãæŸãããã®ã¯ãåäžèŠçŽ ã®ã¢ãã¡ãŒã·ã§ã³ãè¶ ããè€æ°ã®è€éãªã€ã³ã¿ã©ã¯ã·ã§ã³ã調åãããŠç·šæãå§ãããšãã§ãããããããã¢ãã¡ãŒã·ã§ã³ã®åæã®æè¡ã§ãã
ãã®å æ¬çãªã¬ã€ãã§ã¯ãCSSã¹ã¯ããŒã«é§åã¢ãã¡ãŒã·ã§ã³ã®ã¿ã€ã ã©ã€ã³ã®ã³ã¢ã³ã³ã»ãããæ¢æ±ããããããåæãããããã«å¿ èŠãªãã¯ããã¯ãæ·±ãæãäžããŠãããŸããã¬ã€ã€ãŒåããããã©ã©ãã¯ã¹å¹æãé£ç¶çãªã¹ããŒãªãŒããªã³ã°ã®è¡šç€ºããããŠè€éãªã³ã³ããŒãã³ãã®ã€ã³ã¿ã©ã¯ã·ã§ã³ãããã¹ãŠçŽç²ãªCSSã ãã§äœæããæ¹æ³ãåŠã³ãŸãã以äžã®å 容ãã«ããŒããŸãïŒ
- `scroll()`ãš`view()`ã¿ã€ã ã©ã€ã³ã®åºæ¬çãªéãã
- è€æ°ã®èŠçŽ ãåæãããããã®ãç»æçãªååä»ãã¿ã€ã ã©ã€ã³ã®æŠå¿µã
- `animation-range`ã䜿çšããã¢ãã¡ãŒã·ã§ã³åçã®ãã现ãããªå¶åŸ¡ã
- 仿¥ãã䜿ããã³ãŒãä»ãã®å®è·µçã§çŸå®çãªäŸã
- ããã©ãŒãã³ã¹ãã¢ã¯ã»ã·ããªãã£ããã©ãŠã¶äºææ§ã®ããã®ãã¹ããã©ã¯ãã£ã¹ã
CSSã§äœãå¯èœã«ãªãããåèããããªãã®Webäœéšãæ°ããªã¬ãã«ã®ã€ã³ã¿ã©ã¯ãã£ããã£ãšæŽç·ŽããžãšåŒãäžããæºåãããŠãã ããã
åºç€ïŒã¢ãã¡ãŒã·ã§ã³ã¿ã€ã ã©ã€ã³ãçè§£ãã
ã¢ãã¡ãŒã·ã§ã³ãåæãããåã«ããŸãããããé§åããã¡ã«ããºã ãçè§£ããªããã°ãªããŸãããåŸæ¥ãCSSã¢ãã¡ãŒã·ã§ã³ã®ã¿ã€ã ã©ã€ã³ã¯ããã®`animation-duration`ã«ãã£ãŠå®çŸ©ãããæéã®çµéã«åºã¥ããŠããŸãããã¹ã¯ããŒã«é§åã¢ãã¡ãŒã·ã§ã³ã§ã¯ããã®æéãšã®çµã³ã€ããæã¡åãã代ããã«ã¢ãã¡ãŒã·ã§ã³ã®é²è¡åºŠãæ°ãããœãŒã¹ãããªãã¡ããã°ã¬ã¹ã¿ã€ã ã©ã€ã³ã«æ¥ç¶ããŸãã
ããã¯äž»ã«`animation-timeline`ããããã£ã«ãã£ãŠå®çŸãããŸããã¢ãã¡ãŒã·ã§ã³ãããªã¬ãŒãããåŸã«èªå·±å®çµã§å®è¡ãããã®ãåŸ ã€ä»£ããã«ããã®ããããã£ã¯ãã©ãŠã¶ã«å¯ŸããŠãæå®ãããã¿ã€ã ã©ã€ã³ã®é²è¡åºŠã«åºã¥ããŠã¢ãã¡ãŒã·ã§ã³ã®ããŒãã¬ãŒã éãã¹ã¯ã©ãïŒåçã»éåçïŒããããæç€ºããŸããã¿ã€ã ã©ã€ã³ã0%ã®ãšããã¢ãã¡ãŒã·ã§ã³ã¯0%ã®ããŒãã¬ãŒã ã«ãããŸããã¿ã€ã ã©ã€ã³ã50%ã®ãšããã¢ãã¡ãŒã·ã§ã³ã¯50%ã®ããŒãã¬ãŒã ã«ããããšãã£ãå ·åã§ãã
CSS仿§ã§ã¯ããããã®ããã°ã¬ã¹ã¿ã€ã ã©ã€ã³ãäœæããããã«äž»ã«2ã€ã®é¢æ°ãæäŸãããŠããŸãïŒ
- `scroll()`: ã¹ã¯ããŒã«ã³ã³ããïŒã¹ã¯ããŒã©ãŒïŒã®ã¹ã¯ããŒã«é²è¡åºŠã远跡ããå¿åã¿ã€ã ã©ã€ã³ãäœæããŸãã
- `view()`: ç¹å®ã®èŠçŽ ããã¥ãŒããŒãïŒãŸãã¯ä»»æã®ã¹ã¯ããŒã©ãŒïŒãééããéã®å¯èŠæ§ã远跡ããå¿åã¿ã€ã ã©ã€ã³ãäœæããŸãã
確åºããåºç€ãç¯ãããã«ããããããããã詳ããèŠãŠãããŸãããã
æ·±æãïŒ`scroll()`ããã°ã¬ã¹ã¿ã€ã ã©ã€ã³
`scroll()`ãšã¯ïŒ
`scroll()`颿°ã¯ãããŒãžå šäœãŸãã¯ç¹å®ã®ã¹ã¯ããŒã«å¯èœèŠçŽ ã®ã¹ã¯ããŒã«é²è¡åºŠã«å¯Ÿå¿ãã¹ãã¢ãã¡ãŒã·ã§ã³ã«æé©ã§ããå€å žçãªäŸãšããŠã¯ããŠãŒã¶ãŒãããŒãžãäžã«ã¹ã¯ããŒã«ããã«ã€ããŠæºããããŠãããèšäºäžéšã®èªæžé²æããŒããããŸãã
ããã¯ãŠãŒã¶ãŒãã¹ã¯ããŒã©ãŒãã©ãã ãã¹ã¯ããŒã«ããããæž¬å®ããŸããããã©ã«ãã§ã¯ããã¥ã¡ã³ãå šäœã®ã¹ã¯ããŒã«äœçœ®ã远跡ããŸãããããŒãžäžã®ä»»æã®ã¹ã¯ããŒã«å¯èœã³ã³ããã远跡ããããã«èšå®ããããšãã§ããŸãã
æ§æãšãã©ã¡ãŒã¿
`scroll()`颿°ã®åºæ¬çãªæ§æã¯æ¬¡ã®ãšããã§ãïŒ
animation-timeline: scroll(<scroller> <axis>);
ãã®ãã©ã¡ãŒã¿ãåè§£ããŠã¿ãŸãããïŒ
- `<scroller>` (optional): ã©ã®ã¹ã¯ããŒã«ã³ã³ããã®é²è¡åºŠã远跡ããããæå®ããŸãã
root: ããã©ã«ãå€ãããã¥ã¡ã³ãã®ãã¥ãŒããŒãã¹ã¯ããŒã©ãŒïŒã¡ã€ã³ããŒãžã®ã¹ã¯ããŒã«ããŒïŒã衚ããŸããself: èŠçŽ èªèº«ãã¹ã¯ããŒã«ã³ã³ããã§ããå ŽåïŒäŸïŒ`overflow: scroll`ãæã€ïŒããã®èŠçŽ ã®ã¹ã¯ããŒã«äœçœ®ã远跡ããŸããnearest: æãè¿ãç¥å ã®ã¹ã¯ããŒã«ã³ã³ããã®ã¹ã¯ããŒã«äœçœ®ã远跡ããŸãã
- `<axis>` (optional): 远跡ããã¹ã¯ããŒã«è»žãå®çŸ©ããŸãã
block: ããã©ã«ãå€ããããã¯è»žïŒè±èªã®ãããªæ°Žå¹³æžåã¢ãŒãã§ã¯åçŽæ¹åïŒã«æ²¿ã£ãé²è¡åºŠã远跡ããŸããinline: ã€ã³ã©ã€ã³è»žïŒè±èªã§ã¯æ°Žå¹³æ¹åïŒã«æ²¿ã£ãé²è¡åºŠã远跡ããŸããy: åçŽè»žã®æç€ºçãªãšã€ãªã¢ã¹ãx: æ°Žå¹³è»žã®æç€ºçãªãšã€ãªã¢ã¹ã
å®è·µäŸïŒããŒãžã¹ã¯ããŒã«é²æããŒ
ãã®å€å žçãªèªæžé²æã€ã³ãžã±ãŒã¿ãŒãæ§ç¯ããŠã¿ãŸããããããã¯æãã·ã³ãã«ãªåœ¢ã§ã®`scroll()`ã®å®ç§ãªãã¢ã³ã¹ãã¬ãŒã·ã§ã³ã§ãã
HTMLæ§é ïŒ
<div class="progress-bar"></div>
<article>
<h1>A Long Article Title</h1>
<p>... a lot of content here ...</p>
<p>... more content to make the page scrollable ...</p>
</article>
CSSå®è£ ïŒ
/* Define the keyframes for the progress bar */
@keyframes grow-progress {
from { transform: scaleX(0); }
to { transform: scaleX(1); }
}
/* Style the progress bar */
.progress-bar {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 8px;
background-color: dodgerblue;
transform-origin: left; /* Animate scale from the left side */
/* Link the animation to the scroll timeline */
animation: grow-progress linear;
animation-timeline: scroll(root block);
}
/* Basic body styling for demonstration */
body {
font-family: sans-serif;
line-height: 1.6;
padding: 2rem;
height: 300vh; /* Ensure there is plenty to scroll */
}
解説ïŒ
- èŠçŽ ãæ°Žå¹³æ¹åã«0ãã1ãŸã§ã¹ã±ãŒã«ããããã·ã³ãã«ãª`grow-progress`ã¢ãã¡ãŒã·ã§ã³ãå®çŸ©ããŸãã
- `.progress-bar`ã¯ãã¥ãŒããŒãã®äžéšã«åºå®ãããŸãã
- éæ³ã¯æåŸã®2ã€ã®ããããã£ã§èµ·ãããŸãã`grow-progress`ã¢ãã¡ãŒã·ã§ã³ãé©çšããŸããéèŠãªã®ã¯ã`1s`ã®ãããªdurationïŒç¶ç¶æéïŒãäžãã代ããã«ã`animation-timeline`ã`scroll(root block)`ã«èšå®ããããšã§ãã
- ããã¯ãã©ãŠã¶ã«ããã®ã¢ãã¡ãŒã·ã§ã³ãæéçµéã§åçããã®ã§ã¯ãªãããŠãŒã¶ãŒãã«ãŒãããã¥ã¡ã³ããåçŽæ¹åïŒ`block`軞ïŒã«ã¹ã¯ããŒã«ããã®ã«åãããŠããã®ããŒãã¬ãŒã éãã¹ã¯ã©ãããããšäŒããŸãã
ãŠãŒã¶ãŒãããŒãžã®æäžéšïŒã¹ã¯ããŒã«é²è¡åºŠ0%ïŒã«ãããšããããŒã®`scaleX`ã¯0ã«ãªããŸããæäžéšïŒã¹ã¯ããŒã«é²è¡åºŠ100%ïŒã«ãããšãã`scaleX`ã¯1ã«ãªããŸããçµæãšããŠãJavaScriptãäžåå¿ èŠãšããªããå®å šã«ã¹ã ãŒãºãªé²æã€ã³ãžã±ãŒã¿ãŒã宿ããŸãã
è¿æ¥æ§ã®åïŒ`view()`ããã°ã¬ã¹ã¿ã€ã ã©ã€ã³
`view()`ãšã¯ïŒ
`scroll()`ãã³ã³ããå šäœã®é²è¡åºŠã«é¢ãããã®ã§ããã®ã«å¯Ÿãã`view()`ã¯åäžã®èŠçŽ ãã¹ã¯ããŒã©ãŒã®å¯èŠé åãæšªåãæ è·¯ã«é¢ãããã®ã§ããããã¯ãèŠçŽ ãç»é¢ã«å ¥ã£ãŠãããšãã§ãŒãã€ã³ããããã¹ã©ã€ãã¢ããããããããéåžžã«ããããã衚瀺ããããã¢ãã¡ãŒã·ã§ã³ãããããã¿ãŒã³ã®ããã®ãã€ãã£ããªCSSãœãªã¥ãŒã·ã§ã³ã§ãã
`view()`ã¿ã€ã ã©ã€ã³ã¯ãèŠçŽ ãã¹ã¯ããŒã«ããŒãã«åããŠè¡šç€ºããããšãã«å§ãŸããå®å šã«è¡šç€ºé åããå€ãããšãã«çµäºããŸããããã«ããã0%ãã100%ãŸã§ã®ã¿ã€ã ã©ã€ã³ãèŠçŽ ã®å¯èŠæ§ã«çŽæ¥çµã³ã€ããè¡šç€ºå¹æã«ãšã£ãŠéåžžã«çŽæçãªãã®ã«ãªããŸãã
æ§æãšãã©ã¡ãŒã¿
`view()`ã®æ§æã¯å°ãç°ãªããŸãïŒ
animation-timeline: view(<axis> <view-timeline-inset>);
- `<axis>` (optional): `scroll()`ãšåæ§ïŒ`block`, `inline`, `y`, `x`ïŒãèŠçŽ ã®å¯èŠæ§ãã¹ã¯ããŒã«ããŒãã®ã©ã®è»žã«å¯ŸããŠè¿œè·¡ãããããæ±ºå®ããŸãã
- `<view-timeline-inset>` (optional): ããã¯ãã¢ã¯ãã£ããªããã¥ãŒããŒãã®å¢çã調æŽã§ãã匷åãªãã©ã¡ãŒã¿ã§ãã1ã€ãŸãã¯2ã€ã®å€ïŒããããéå§ãšçµäºã®ã€ã³ã»ããçšïŒãåãåãããšãã§ããŸããããŒã»ã³ããŒãžãåºå®é·ã䜿çšã§ããŸããäŸãã°ã`100px 20%`ã¯ãã¿ã€ã ã©ã€ã³ããã¥ãŒããŒããäžãã100pxãäžãã20%ã®äœçœ®ããå§ãŸããšèŠãªãããšãæå³ããŸããããã«ãããç»é¢äžã®èŠçŽ ã®äœçœ®ã«å¯ŸããŠã¢ãã¡ãŒã·ã§ã³ããã€éå§ã»çµäºãããã埮調æŽã§ããŸãã
å®è·µäŸïŒè¡šç€ºæã«ãã§ãŒãã€ã³
ã³ã³ãã³ãã«ãŒããç»é¢ã«ã¹ã¯ããŒã«ãããã«ã€ããŠãã§ãŒãã€ã³ããã¹ã©ã€ãããŠè¡šç€ºããããšããå€å žçãªå¹æãäœæããŠã¿ãŸãããã
HTMLæ§é ïŒ
<section class="content-grid">
<div class="card">Card 1</div>
<div class="card">Card 2</div>
<div class="card">Card 3</div>
<div class="card">Card 4</div>
</section>
CSSå®è£ ïŒ
/* Define keyframes for the reveal animation */
@keyframes fade-in-up {
from {
opacity: 0;
transform: translateY(50px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.card {
/* Apply the animation to each card */
animation: fade-in-up linear;
animation-timeline: view(); /* This is it! */
/* Other styling */
background-color: #f0f0f0;
padding: 2rem;
border-radius: 8px;
min-height: 200px;
display: grid;
place-content: center;
font-size: 2rem;
}
/* Layout styling */
.content-grid {
display: grid;
gap: 2rem;
padding: 10vh 2rem;
}
解説ïŒ
- `fade-in-up`ããŒãã¬ãŒã ã¯ãç§ãã¡ãæãã¢ãã¡ãŒã·ã§ã³ãå®çŸ©ããŸãïŒæåã¯éæã§å°ãäœãäœçœ®ããå§ãŸããæåŸã¯äžéæã§æçµçãªäœçœ®ã«åãŸããŸãã
- å`.card`èŠçŽ ã«ãã®ã¢ãã¡ãŒã·ã§ã³ãé©çšãããŸãã
- éèŠãªè¡ã¯`animation-timeline: view();`ã§ããããã«ãããåã«ãŒãã«å¯ŸããŠãŠããŒã¯ãªå¿åã®ã¿ã€ã ã©ã€ã³ãäœæãããŸãã
- åã ã®ã«ãŒãããšã«ããã®ã¢ãã¡ãŒã·ã§ã³ã¯ãã¥ãŒããŒãã«å ¥ãå§ããæç¹ã§0%ã«ãªãããã¥ãŒããŒãããå®å šã«åºçµãã£ãæç¹ã§100%ã«éããŸãã
ããŒãžãäžã«ã¹ã¯ããŒã«ãããšãåã«ãŒãã¯ãã¥ãŒã«å ¥ããšåæã«æ£ç¢ºã«ãã¹ã ãŒãºã«ã¢ãã¡ãŒã·ã§ã³ã§æå®ã®äœçœ®ã«åãŸããŸããããã¯ã以åã¯JavaScriptã®Intersection Observerãšæ éãªç¶æ 管çãå¿ èŠãšãã忥ãããã£ã2è¡ã®CSSã§å®çŸããŠããŸãã
æ¬é¡ïŒã¢ãã¡ãŒã·ã§ã³ã®åæ
å¿åã®`scroll()`ããã³`view()`ã¿ã€ã ã©ã€ã³ã®äœ¿çšã¯ãç¬ç«ãã广ã«ã¯åŒ·åã§ããããããè€æ°ã®èŠçŽ ãåãã¿ã€ã ã©ã€ã³ã«åå¿ããããã«ãããå Žåã¯ã©ãã§ããããïŒèæ¯ç»åãã¿ã€ãã«ã忝èŠçŽ ããã¹ãŠç°ãªãé床ã§åããããã¹ãŠåãã¹ã¯ããŒã«ã¢ã¯ã·ã§ã³ã«ãã£ãŠé§åããããã©ã©ãã¯ã¹å¹æãæ³åããŠã¿ãŠãã ããããããã¯ã補åã®æ©èœãªã¹ããã¹ã¯ããŒã«ããŠéãéããéã«ã補åç»åãå€åœ¢ãããããªå Žåã§ãã
ããã§åæãç»å Žãããã®éµã¯å¿åã¿ã€ã ã©ã€ã³ããååä»ãã¿ã€ã ã©ã€ã³ã«ç§»è¡ããããšã§ãã
ãªãåæããã®ãïŒ
åæã«ãããè±ãã§ç©èªæ§ã®ããäœéšã®åµé ãå¯èœã«ãªããŸããç¬ç«ããã¢ãã¡ãŒã·ã§ã³ã®éåã§ã¯ãªãããŠãŒã¶ãŒãã¹ã¯ããŒã«ããã«ã€ããŠé²åããããŸãšãŸãã®ããã·ãŒã³ãæ§ç¯ã§ããŸããããã¯ä»¥äžã®ããã«äžå¯æ¬ ã§ãïŒ
- è€éãªãã©ã©ãã¯ã¹å¹æïŒ åäžã®ã¹ã¯ããŒã«ããªã¬ãŒã«å¯ŸããŠç°ãªãã¬ã€ã€ãŒãæ§ã ãªé床ã§åããããšã«ããã奥è¡ãæãåµåºããŸãã
- å調ããã³ã³ããŒãã³ãã®ç¶æ ïŒ è€éãªUIã³ã³ããŒãã³ãããã¥ãŒã«å ¥ã£ãŠããéã«ããã®ç°ãªãéšåãäžäœãšãªã£ãŠã¢ãã¡ãŒã·ã§ã³ãããŸãã
- ããžã¥ã¢ã«ã¹ããŒãªãŒããªã³ã°ïŒ ãŠãŒã¶ãŒãç©èªã«å°ãããã«ãæ éã«æ¯ãä»ããããé åºã§èŠçŽ ã衚瀺ã»å€åœ¢ãããŸãã
ãã¯ããã¯ïŒå ±æãããååä»ãã¿ã€ã ã©ã€ã³
åæã®ã¡ã«ããºã ã«ã¯ã3ã€ã®æ°ããCSSããããã£ãé¢ãã£ãŠããŸãïŒ
- `timeline-scope`: ã³ã³ããèŠçŽ ã«é©çšãããŸãããã®äžã§å®çŸ©ãããååä»ãã¿ã€ã ã©ã€ã³ãä»ã®èŠçŽ ããèŠã€ããããã¹ã³ãŒãã確ç«ããŸãã
- `scroll-timeline-name` / `view-timeline-name`: èŠçŽ ã«é©çšãããã¿ã€ã ã©ã€ã³ãäœæãååãä»ããŸããååã¯ããã·ã¥èå¥åïŒäŸïŒ`--my-timeline`ïŒã§ãªããã°ãªããŸããããã®èŠçŽ ã®ã¹ã¯ããŒã«é²è¡åºŠïŒ`scroll-timeline-name`ïŒãŸãã¯å¯èŠæ§ïŒ`view-timeline-name`ïŒããååä»ãã¿ã€ã ã©ã€ã³ã®ãœãŒã¹ã«ãªããŸãã
- `animation-timeline`: ããã¯ä»¥åã«ãèŠãŸããããä»åºŠã¯`scroll()`ã`view()`ã䜿çšãã代ããã«ãå ±æã¿ã€ã ã©ã€ã³ã®ããã·ã¥èå¥ååïŒäŸïŒ`animation-timeline: --my-timeline;`ïŒãæž¡ããŸãã
ããã»ã¹ã¯ä»¥äžã®éãã§ãïŒ 1. ç¥å èŠçŽ ã`timeline-scope`ãå®çŸ©ããŸãã 2. åå«èŠçŽ ã`view-timeline-name`ãŸãã¯`scroll-timeline-name`ã䜿çšããŠã¿ã€ã ã©ã€ã³ãå®çŸ©ããååãä»ããŸãã 3. ä»ã®ä»»æã®åå«èŠçŽ ãããã®ååã`animation-timeline`ããããã£ã§äœ¿çšããŠãåãã¿ã€ã ã©ã€ã³ã«æ¥ç¶ã§ããŸãã
å®è·µäŸïŒå€å±€ãã©ã©ãã¯ã¹ã·ãŒã³
èæ¯ç»åãããŒãžãããé ãã¹ã¯ããŒã«ããã¿ã€ãã«ãããéããã§ãŒãã¢ãŠããããå€å žçãªãã©ã©ãã¯ã¹ããããŒãæ§ç¯ããŸãããã
HTMLæ§é ïŒ
<div class="parallax-container">
<div class="parallax-background"></div>
<h1 class="parallax-title">Synchronized Motion</h1>
</div>
<div class="content">
<p>... main page content ...</p>
</div>
CSSå®è£ ïŒ
/* 1. Define a scope for our named timeline */
.parallax-container {
timeline-scope: --parallax-scene;
position: relative;
height: 100vh;
display: grid;
place-items: center;
}
/* 2. Define the timeline itself using the container's visibility */
/* The container's journey through the viewport will drive the animations */
.parallax-container {
view-timeline-name: --parallax-scene;
}
/* 3. Define the keyframes for each layer */
@keyframes move-background {
to {
transform: translateY(30vh); /* Moves slower */
}
}
@keyframes fade-title {
to {
opacity: 0;
transform: scale(0.8);
}
}
/* 4. Style the layers and hook them to the named timeline */
.parallax-background {
position: absolute;
inset: -30vh 0 0 0; /* Extra height to allow for movement */
background: url('https://picsum.photos/1600/1200') no-repeat center center/cover;
z-index: -1;
/* Attach to the shared timeline */
animation: move-background linear;
animation-timeline: --parallax-scene;
}
.parallax-title {
color: white;
font-size: 5rem;
text-shadow: 0 0 10px rgba(0,0,0,0.7);
/* Attach to the same shared timeline */
animation: fade-title linear;
animation-timeline: --parallax-scene;
}
解説ïŒ
- `.parallax-container`ã¯`--parallax-scene`ãšããååã®`timeline-scope`ã確ç«ããŸããããã«ããããã®ååãåèŠçŽ ã§å©çšå¯èœã«ãªããŸãã
- 次ã«ãåãèŠçŽ ã«`view-timeline-name: --parallax-scene;`ã远å ããŸããããã¯ã`--parallax-scene`ãšããååã®ã¿ã€ã ã©ã€ã³ãã`.parallax-container`èªäœã®å¯èŠæ§ã«åºã¥ã`view()`ã¿ã€ã ã©ã€ã³ã«ãªãããšãæå³ããŸãã
- 埮åŠãªåçŽæ¹åã®ã·ããã®ããã®`move-background`ãšããã§ãŒãïŒã¹ã±ãŒã«å¹æã®ããã®`fade-title`ãšãã2ã€ã®ç°ãªãã¢ãã¡ãŒã·ã§ã³ãäœæããŸãã
- 決å®çã«éèŠãªã®ã¯ã`.parallax-background`ãš`.parallax-title`ã®äž¡æ¹ã§ã`animation-timeline`ããããã£ã`--parallax-scene`ã«èšå®ãããŠããããšã§ãã
ããã§ã`.parallax-container`ããã¥ãŒããŒããã¹ã¯ããŒã«ããã«ã€ããŠãåäžã®é²è¡åºŠïŒprogress valueïŒãçæãããŸããèæ¯ãšã¿ã€ãã«ã®äž¡æ¹ãããã®åãå€ã䜿çšããŠããããã®ã¢ãã¡ãŒã·ã§ã³ãé§åããŸããããŒãã¬ãŒã ã¯å®å šã«ç°ãªããŸãããåçã¯å®ç§ã«åæããããŸãšãŸãã®ããå°è±¡çãªèŠèŠå¹æãçã¿åºããŸãã
`animation-range`ã«ããé«åºŠãªåæ
ååä»ãã¿ã€ã ã©ã€ã³ã¯ãã¢ãã¡ãŒã·ã§ã³ãäžäœãšãªã£ãŠåçãããã®ã«çŽ æŽãããæ©èœã§ããããããããããé çªã«åçããããå Žåããããã¢ãã¡ãŒã·ã§ã³ãå¥ã®èŠçŽ ã®å¯èŠæ§ã®ç¹å®ã®éšåã§ã®ã¿ããªã¬ãŒãããå Žåã¯ã©ãã§ããããïŒããã§ã`animation-range`ããããã£ãã¡ããªãŒããããäžæ®µéäžã®åŒ·åãªå¶åŸ¡ãæäŸããŸãã
0%ãã100%ãè¶ ããŠ
ããã©ã«ãã§ã¯ãã¢ãã¡ãŒã·ã§ã³ã¯ãã®ã¿ã€ã ã©ã€ã³ã®å šæéã«ãããã³ã°ãããŸãã`animation-range`ã䜿çšãããšãã¢ãã¡ãŒã·ã§ã³ã®ããŒãã¬ãŒã ã®0%ãš100%ã®ç¹ã«å¯Ÿå¿ãã¹ãã¿ã€ã ã©ã€ã³ã®ç¹å®ã®éå§ç¹ãšçµäºç¹ãå®çŸ©ã§ããŸãã
ããã«ãããããã®ã¢ãã¡ãŒã·ã§ã³ããèŠçŽ ãç»é¢ã®20%ã«å ¥ã£ããšãã«éå§ãã50%ã®ããŒã¯ã«å°éãããŸã§ã«çµäºãããããšãã£ãæç€ºãå¯èœã«ãªããŸãã
`animation-range`ã®å€ãçè§£ãã
æ§æã¯`animation-range-start`ãš`animation-range-end`ããŸãã¯ã·ã§ãŒããã³ãã®`animation-range`ã§ãã
animation-range: <start-range> <end-range>;
å€ã¯ãç¹å¥ãªããŒã¯ãŒããšããŒã»ã³ããŒãžã®çµã¿åããã«ããããšãã§ããŸãã`view()`ã¿ã€ã ã©ã€ã³ã®å Žåãæãäžè¬çãªããŒã¯ãŒãã¯æ¬¡ã®ãšããã§ãïŒ
entry: èŠçŽ ã®ããŒããŒããã¯ã¹ãã¹ã¯ããŒã«ããŒãã®çµäºèŸºã暪åãç¬éãexit: èŠçŽ ã®ããŒããŒããã¯ã¹ãã¹ã¯ããŒã«ããŒãã®éå§èŸºã暪åãç¬éãcover: èŠçŽ ãã¹ã¯ããŒã«ããŒããå®å šã«èŠã£ãŠããæéå šäœãã€ãŸãå®å šã«èŠã£ãç¬éããèŠããªããªãç¬éãŸã§ãæããŸããcontain: èŠçŽ ãã¹ã¯ããŒã«ããŒãå ã«å®å šã«å«ãŸããŠããæéãæããŸãã
ãããã«ããŒã»ã³ããŒãžã®ãªãã»ããã远å ããããšãã§ããŸããäŸãã°ã`entry 0%`ïŒããã©ã«ãã®éå§ïŒã`entry 100%`ïŒèŠçŽ ã®äžèŸºããã¥ãŒããŒãã®äžèŸºã«éãããšãïŒã`exit 0%`ã`exit 100%`ãªã©ã§ãã
å®è·µäŸïŒé£ç¶çãªã¹ããŒãªãŒããªã³ã°ã·ãŒã³
ã¹ã¯ããŒã«ããŠéãéããéã«åé ç®ããã€ã©ã€ããããæ©èœãªã¹ããäœæããŸããããå®ç§ãªå調ã®ããã«åäžã®å ±æã¿ã€ã ã©ã€ã³ã䜿çšããŸãã
HTMLæ§é ïŒ
<div class="feature-list-container">
<div class="feature-list-timeline-marker"></div>
<div class="feature-item">
<h3>Feature One: Global Reach</h3>
<p>Our services are available worldwide.</p>
</div>
<div class="feature-item">
<h3>Feature Two: Unbeatable Speed</h3>
<p>Experience next-generation performance.</p>
</div>
<div class="feature-item">
<h3>Feature Three: Ironclad Security</h3>
<p>Your data is always protected.</p>
</div>
</div>
CSSå®è£ ïŒ
/* Define the scope on the main container */
.feature-list-container {
timeline-scope: --feature-list;
position: relative;
padding: 50vh 0; /* Give space for scrolling */
}
/* Use a dedicated empty div to define the timeline's source */
.feature-list-timeline-marker {
view-timeline-name: --feature-list;
position: absolute;
inset: 0;
}
/* Keyframes for highlighting an item */
@keyframes highlight-feature {
to {
background-color: lightgoldenrodyellow;
transform: scale(1.02);
}
}
.feature-item {
width: 80%;
margin: 5rem auto;
padding: 2rem;
border: 1px solid #ccc;
border-radius: 8px;
transition: background-color 0.3s, transform 0.3s;
/* Attach animation and the shared timeline */
animation: highlight-feature linear both;
animation-timeline: --feature-list;
}
/* The magic of animation-range for sequencing */
.feature-item:nth-of-type(1) {
animation-range: entry 5% entry 40%;
}
.feature-item:nth-of-type(2) {
animation-range: entry 35% entry 70%;
}
.feature-item:nth-of-type(3) {
animation-range: entry 65% entry 100%;
}
解説ïŒ
- `--feature-list`ã¹ã³ãŒãã確ç«ããã³ã³ããå šäœã«åºãã空ã®ããŒã«ãŒdivã«çµã³ã€ããããååä»ã`view()`ã¿ã€ã ã©ã€ã³ãäœæããŸãããã®åäžã®ã¿ã€ã ã©ã€ã³ããæ©èœã»ã¯ã·ã§ã³å šäœã®å¯èŠæ§ã远跡ããŸãã
- å`.feature-item`ã¯ããã®åã`--feature-list`ã¿ã€ã ã©ã€ã³ã«ãªã³ã¯ãããåã`highlight-feature`ã¢ãã¡ãŒã·ã§ã³ãäžããããŸãã
- éèŠãªéšåã¯`animation-range`ã§ããããããªããã°ã3ã€ã®é ç®ãã¹ãŠããã³ã³ããããã¥ãŒã«å ¥ãã®ãšåæã«ãã€ã©ã€ããããŠããŸããŸãã
- 代ããã«ãç°ãªãç¯å²ãå²ãåœãŠãŸãïŒ
- æåã®é ç®ã¯ãã¿ã€ã ã©ã€ã³ã®é²è¡åºŠã®5%ãã40%ã®éã§ã¢ãã¡ãŒã·ã§ã³ããŸãã
- 2çªç®ã®é ç®ã¯ã35%ãã70%ã®ãŠã£ã³ããŠã®éã«ã¢ãã¡ãŒã·ã§ã³ããŸãã
- 3çªç®ã®é ç®ã¯ã65%ãã100%ãŸã§ã¢ãã¡ãŒã·ã§ã³ããŸãã
ããã«ãããæ¥œããé£ç¶çãªå¹æãçãŸããŸããã¹ã¯ããŒã«ãããšãæåã®æ©èœããã€ã©ã€ããããŸããã¹ã¯ããŒã«ãç¶ãããšãããããã§ãŒãããã¯ããéã«2çªç®ã®æ©èœããã€ã©ã€ãããããšããããã«ç¶ããŸããéè€ããç¯å²ïŒ`entry 40%`ãš`entry 35%`ïŒãã¹ã ãŒãºãªåŒãç¶ããçã¿åºããŸãããã®é«åºŠãªã·ãŒã±ã³ã¹ãšåæã¯ããããæ°è¡ã®å®£èšçãªCSSã§å®çŸãããŠããŸãã
ããã©ãŒãã³ã¹ãšãã¹ããã©ã¯ãã£ã¹
CSSã¹ã¯ããŒã«é§åã¢ãã¡ãŒã·ã§ã³ã¯éåžžã«åŒ·åã§ããã責任ãæã£ãŠäœ¿çšããããšãéèŠã§ããããã§ã¯ãã°ããŒãã«ãªãªãŒãã£ãšã³ã¹ã«åããäž»èŠãªãã¹ããã©ã¯ãã£ã¹ãããã€ã玹ä»ããŸãã
ããã©ãŒãã³ã¹äžã®å©ç¹
ãã®æè¡ã®äž»ãªå©ç¹ã¯ããã©ãŒãã³ã¹ã§ããã¡ã€ã³ã¹ã¬ããã§å®è¡ãããä»ã®ã¿ã¹ã¯ã«ãã£ãŠãããã¯ãããå¯èœæ§ã®ããJavaScriptããŒã¹ã®ã¹ã¯ããŒã«ãªã¹ããŒãšã¯ç°ãªããCSSã¹ã¯ããŒã«é§åã¢ãã¡ãŒã·ã§ã³ã¯ã³ã³ããžã¿ãŒã¹ã¬ããã§å®è¡ãããŸããããã¯ãã¡ã€ã³ã¹ã¬ãããããžãŒãªç¶æ ã§ããã·ã«ã¯ã®ããã«æ»ãããªãŸãŸã§ããããšãæå³ããŸãããã®å©ç¹ãæå€§åããããã«ãäž»ã«`transform`ãš`opacity`ãšãã£ããåæã³ã¹ãã®äœãããããã£ã®ã¢ãã¡ãŒã·ã§ã³ã«åºå·ããŠãã ããã
ã¢ã¯ã»ã·ããªãã£ãžã®é æ ®
誰ããWebããŒãžäžã®åããæãã§ããããã§ãã蚱容ã§ããããã§ããããŸããããŠãŒã¶ãŒã®å¥œã¿ãå°éããããšãäžå¯æ¬ ã§ãããªãã¬ãŒãã£ã³ã°ã·ã¹ãã ã§ãã®èšå®ãæå¹ã«ããŠãããŠãŒã¶ãŒã®ããã«ã`prefers-reduced-motion`ã¡ãã£ã¢ã¯ãšãªã䜿çšããŠã¢ãã¡ãŒã·ã§ã³ãç¡å¹åãŸãã¯è»œæžããŠãã ããã
@media (prefers-reduced-motion: reduce) {
.card,
.parallax-background,
.parallax-title,
.feature-item {
/* Disable the animations */
animation: none;
/* Ensure elements are in their final, visible state */
opacity: 1;
transform: none;
}
}
ãã©ãŠã¶ã®ãµããŒããšãã©ãŒã«ããã¯
2023幎åŸåçŸåšãCSSã¹ã¯ããŒã«é§åã¢ãã¡ãŒã·ã§ã³ã¯ChromiumããŒã¹ã®ãã©ãŠã¶ïŒChromeãEdgeïŒã§ãµããŒããããŠãããFirefoxãšSafariã§ã掻çºã«éçºãé²ããããŠããŸããã°ããŒãã«ãªãªãŒãã£ãšã³ã¹ã察象ãšããå Žåããã®æ©èœããŸã ãµããŒãããŠããªããã©ãŠã¶ãèæ ®ããå¿ èŠããããŸãã`@supports`ã¢ããã«ãŒã«ã䜿çšããŠããµããŒããããŠããå Žåã«ã®ã¿ã¢ãã¡ãŒã·ã§ã³ãé©çšããŠãã ããã
/* Default state for non-supporting browsers */
.card {
opacity: 1;
transform: translateY(0);
}
/* Apply animations only in supporting browsers */
@supports (animation-timeline: view()) {
.card {
opacity: 0; /* Initial state for animation */
transform: translateY(50px);
animation: fade-in-up linear;
animation-timeline: view();
}
}
ãã®ããã°ã¬ãã·ããšã³ãã³ã¹ã¡ã³ãã®ã¢ãããŒãã¯ããã¹ãŠã®ãŠãŒã¶ãŒã«æ©èœçãªäœéšãä¿èšŒããã¢ãã³ãªãã©ãŠã¶ã䜿çšããŠãããŠãŒã¶ãŒã«ã¯åŒ·åãããã¢ãã¡ãŒã·ã§ã³äœéšãæäŸããŸãã
ãããã°ã®ãã³ã
çŸä»£ã®ãã©ãŠã¶éçºè ããŒã«ã¯ãã¹ã¯ããŒã«é§åã¢ãã¡ãŒã·ã§ã³ã®ãããã°ãµããŒãã远å ããŠããŸããäŸãã°ãChrome DevToolsã§ã¯ãèŠçŽ ãã€ã³ã¹ãã¯ãããŠãAnimationsãããã«ã«æ°ããã»ã¯ã·ã§ã³ãèŠã€ããããšãã§ããŸããããã«ãããã¿ã€ã ã©ã€ã³ã®é²è¡ç¶æ³ã確èªããããæåã§ã¹ã¯ã©ããããããããšãã§ãã`animation-range`ã®å€ã埮調æŽããã®ãã¯ããã«ç°¡åã«ãªããŸãã
çµè«ïŒæªæ¥ã¯ã¹ã¯ããŒã«é§å
CSSã¹ã¯ããŒã«é§åã¢ãã¡ãŒã·ã§ã³ãç¹ã«ååä»ãã¿ã€ã ã©ã€ã³ã§ããããåæãããèœåã¯ãWebãã¶ã€ã³ãšéçºã«ãšã£ãŠèšå¿µç¢çãªé£èºã衚ããŠããŸããç§ãã¡ã¯ãåœä»€çã§ãã°ãã°è匱ãªJavaScriptãœãªã¥ãŒã·ã§ã³ããã宣èšçã§ãããã©ãŒãã³ã¹ãé«ããã¢ã¯ã»ã¹ããããCSSãã€ãã£ãã®ã¢ãããŒããžãšç§»è¡ããŸããã
ç§ãã¡ã¯ãããããããŒãžã¬ãã«ãšèŠçŽ ã¬ãã«ã®é²è¡åºŠãæ±ã`scroll()`ãš`view()`ã¿ã€ã ã©ã€ã³ã®åºç€æŠå¿µãæ¢æ±ããŸãããããã«éèŠãªããšãšããŠã`timeline-scope`ãš`view-timeline-name`ã䜿çšããŠå ±æãããååä»ãã¿ã€ã ã©ã€ã³ãäœæããããšã§ãåæã®åãè§£ãæŸã¡ãŸãããããã«ããããã©ã©ãã¯ã¹ã·ãŒã³ã®ãããªè€éã§å調ããèŠèŠçãªç©èªãæ§ç¯ã§ããŸããæåŸã«ã`animation-range`ã«ãã£ãŠãã¢ãã¡ãŒã·ã§ã³ãã·ãŒã±ã³ã¹åããè€éã§éè€ããã€ã³ã¿ã©ã¯ã·ã§ã³ãäœæããããã®ãã现ãããªå¶åŸ¡ãæã«å ¥ããŸããã
ãããã®ãã¯ããã¯ããã¹ã¿ãŒããããšã§ãããªãã¯ãã¯ãåã«WebããŒãžãæ§ç¯ããŠããã ãã§ã¯ãããŸããããã€ãããã¯ã§ãé åçã§ãé«ããã©ãŒãã³ã¹ãªããžã¿ã«ã¹ããŒãªãŒãäœãäžããŠããã®ã§ãããã©ãŠã¶ã®ãµããŒããæ¡å€§ãç¶ããã«ã€ããŠããããã®ããŒã«ã¯ãã¹ãŠã®ããã³ããšã³ãéçºè ã®ããŒã«ãããã«äžå¯æ¬ ãªäžéšãšãªãã§ããããWebã€ã³ã¿ã©ã¯ã·ã§ã³ã®æªæ¥ã¯ããã«ãããããã¯ã¹ã¯ããŒã«ããŒã«ãã£ãŠé§åãããŸãã